package com.hyacinth.utils;

import com.hyacinth.lang.Singleton;
import com.hyacinth.structure.SimpleCache;
import com.hyacinth.utils.collect.CollectionUtils;
import com.hyacinth.utils.exception.UtilException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 类加载工具类
 * @author zhangfb
 * @version 1.0.0.1
 * @since JDK 1.8
 */
public class ClassUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(ClassUtils.class);

    /** 数组类的结尾符: "[]" */
    private static final String ARRAY_SUFFIX = "[]";
    /** 内部数组类名前缀: "[" */
    private static final String INTERNAL_ARRAY_PREFIX = "[";
    /** 内部非原始类型类名前缀: "[L" */
    private static final String NON_PRIMITIVE_ARRAY_PREFIX = "[L";
    /** 包名分界符: '.' */
    private static final char PACKAGE_SEPARATOR = StringUtils.C_DOT;
    /** 内部类分界符: '$' */
    private static final char INNER_CLASS_SEPARATOR = '$';

    private static final String CLASS_SUFFIX = ".class";
    private static final String PROTOCOL_FILE = "file";
    private static final String PROTOCOL_JAR = "jar";

    private static Set<Class<?>> classes = null;

    private static ClassLoader defaultClassLoader;
    private static ClassLoader systemClassLoader;

    /** 原始类型包装类-简单类映射 **/
    private static final Map<Class<?>, Class<?>> primitiveWrapperTypeMap = new IdentityHashMap<>(8);
    /** 原始类型简单类-包装类映射 **/
    private static final Map<Class<?>, Class<?>> primitiveTypeToWrapperMap = new IdentityHashMap<>(8);
    /** 原始类型名称-类型映射 **/
    private static final Map<String, Class<?>> primitiveTypeNameMap = new HashMap<>(32);
    /** java本地接口集合 **/
    private static Set<Class<?>> javaLanguageInterfaces;
    /**
     * java本地类集合
     */
    private static final Map<String, Class<?>> commonClassCache = new HashMap<>(64);

    private static SimpleCache<String, Class<?>> classCache = new SimpleCache<>();

    private ClassUtils() {
        try {
            primitiveWrapperTypeMap.put(Boolean.class, boolean.class);
            primitiveWrapperTypeMap.put(Byte.class, byte.class);
            primitiveWrapperTypeMap.put(Character.class, char.class);
            primitiveWrapperTypeMap.put(Double.class, double.class);
            primitiveWrapperTypeMap.put(Float.class, float.class);
            primitiveWrapperTypeMap.put(Integer.class, int.class);
            primitiveWrapperTypeMap.put(Long.class, long.class);
            primitiveWrapperTypeMap.put(Short.class, short.class);

            primitiveWrapperTypeMap.forEach((key, value) -> {
                primitiveTypeToWrapperMap.put(value, key);
                registerCommonClasses(key);
            });

            Set<Class<?>> primitiveTypes = new HashSet<>(32);
            primitiveTypes.addAll(primitiveWrapperTypeMap.values());
            Collections.addAll(primitiveTypes, boolean[].class, byte[].class, char[].class,
                    double[].class, float[].class, int[].class, long[].class, short[].class);
            primitiveTypes.add(void.class);
            for (Class<?> primitiveType : primitiveTypes) {
                primitiveTypeNameMap.put(primitiveType.getName(), primitiveType);
            }

            registerCommonClasses(Boolean[].class, Byte[].class, Character[].class, Double[].class,
                    Float[].class, Integer[].class, Long[].class, Short[].class);
            registerCommonClasses(Number.class, Number[].class, String.class, String[].class,
                    Class.class, Class[].class, Object.class, Object[].class);
            registerCommonClasses(Throwable.class, Exception.class, RuntimeException.class,
                    Error.class, StackTraceElement.class, StackTraceElement[].class);
            registerCommonClasses(Enum.class, Iterable.class, Iterator.class, Enumeration.class,
                    Collection.class, List.class, Set.class, Map.class, Map.Entry.class, Optional.class);

            Class<?>[] javaLanguageInterfaceArray = {Serializable.class, Externalizable.class,
                    Closeable.class, AutoCloseable.class, Cloneable.class, Comparable.class};
            registerCommonClasses(javaLanguageInterfaceArray);
            javaLanguageInterfaces = new HashSet<>(Arrays.asList(javaLanguageInterfaceArray));
            defaultClassLoader = getDefaultClassLoader();
            systemClassLoader = ClassLoader.getSystemClassLoader();
        } catch (SecurityException ignored) {
            // AccessControlException on Google App Engine
        }
    }

    private static void registerCommonClasses(Class<?>... commonClasses) {
        for (Class<?> clazz : commonClasses) {
            commonClassCache.put(clazz.getName(), clazz);
        }
    }

    /**
     * 加载包下所有的子类
     * @param packageName 包名
     * @return all classes
     */
    public static <T> Set<Class<? extends T>> getSubClasses(String packageName, Class<T> clz) {
        Set<Class<?>> allClasses = getAllClasses(packageName);
        Set<Class<? extends T>> subClasses = new HashSet<>(16);
        if (!CollectionUtils.isEmpty(allClasses)) {
            for (Class<?> cc : allClasses) {
                if (clz.isAssignableFrom(cc) && !clz.equals(cc)) {
                    subClasses.add((Class<? extends T>) cc);
                }
            }
        }
        return subClasses;
    }

    /**
     * 加载包下所有的类
     * @param packageName 包名
     * @return all classes
     */
    public static Set<Class<?>> getAllClasses(String packageName) {
        if (classes == null) {
            classes = new HashSet<>(32);
            loadClassesByPackName(packageName, false, classes);
        }
        return classes;
    }

    /**
     * 加载包下面的所有类集合
     * @param packageName 包名
     * @param initializtion 是否初始化
     * @param set 类集合
     */
    private static void loadClassesByPackName(String packageName, boolean initializtion, Set<Class<?>> set) {

        String packageDirName = resourceName(packageName);

        try {
            Enumeration<URL> dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
            while (dirs.hasMoreElements()) {
                URL url = dirs.nextElement();
                String protocol = url.getProtocol();
                if (PROTOCOL_FILE.equals(protocol)) {
                    String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                    loadClassesInPackByFile(packageName, filePath, initializtion, set);
                } else if (PROTOCOL_JAR.equals(protocol)) {
                    JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile();
                    loadClassesInPackByJar(jar, packageDirName, packageName, initializtion, set);
                }
            }
        } catch (IOException e) {
            LOGGER.error("IOException", e);
        }
    }

    /**
     * 加载包下面的所有文件
     * @param packageName 包名
     * @param packagePath 包路径
     * @param initializtion 是否初始化
     * @param classes 文件集合
     */
    private static void loadClassesInPackByFile(String packageName, String packagePath, boolean initializtion, Set<Class<?>> classes) {
        File dir = new File(packagePath);
        if (!dir.exists() || !dir.isDirectory()) {
            return;
        }
        File[] files = dir.listFiles(file -> file.isDirectory() || file.getName().endsWith(CLASS_SUFFIX));
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    loadClassesInPackByFile(packageName + "." + file.getName(), file.getAbsolutePath(), initializtion, classes);
                } else {
                    String className = file.getName().substring(0, file.getName().length() - 6);
                    classes.add(initClass(initializtion, packageName + '.' + className));
                }
            }
        }
    }

    /**
     * 加载包下面的所有文件
     * @param packageName 包名
     * @param packageDirName 保路径
     * @param classes 文件集合
     */
    private static void loadClassesInPackByJar(JarFile jar, String packageDirName, String packageName, boolean initializtion, Set<Class<?>> classes) {
        Enumeration<JarEntry> entries = jar.entries();
        while (entries.hasMoreElements()) {
            JarEntry entry = entries.nextElement();
            String name = entry.getName();
            if (name.charAt(0) == '/') {
                name = name.substring(1);
            }
            if (name.startsWith(packageDirName)) {
                int idx = name.lastIndexOf('/');
                if (idx != -1) {
                    packageName = name.substring(0, idx).replace('/', '.');
                }
                if (name.endsWith(CLASS_SUFFIX) && !entry.isDirectory()) {
                    String className = name.substring(packageName.length() + 1, name.length() - 6);
                    classes.add(initClass(initializtion, packageName + '.' + className));
                }
            }
        }
    }

    /**
     * 初始化类
     * @param initializtion 是否初始化
     * @param className 类名称
     */
    public static Class<?> initClass(boolean initializtion, String className) {
        Class<?> clz = null;
        try {
            if (!initializtion) {
                clz = Class.forName(className, false, getDefaultClassLoader());
            } else {
                clz = Class.forName(className);
            }
        } catch (ClassNotFoundException e) {
            LOGGER.error("ClassNotFoundException", e);
        }
        return clz;
    }

    /**
     * 包名转换为资源名
     * @param packName 包名 com.hyacinth.dubbo.io
     * @return 资源名
     */
    private static String resourceName(String packName) {
        if (packName != null) {
            String resourceName = packName.replace(".", "\\");
            if (resourceName.startsWith("/")) {
                resourceName = resourceName.substring(1);
            }
            return resourceName;
        }
        return null;
    }

    /**
     * 根据类名加载类
     */
    public static Class<?> classForName(String className) throws ClassNotFoundException {
        try {
            Class<?> c = Class.forName(className, true, getDefaultClassLoader());
            if (null != c) {
                return c;
            }
        } catch (ClassNotFoundException e) {
            // we'll ignore this until all classloaders fail to locate the class
        }
        throw new ClassNotFoundException("Cannot find class: " + className);
    }

    /**
     * 根据类名加载类
     * @param name 类名
     * @param classLoader 类加载器
     */
    public static Class<?> classForName(String name, ClassLoader[] classLoader) throws ClassNotFoundException {
        for (ClassLoader cl : classLoader) {
            if (null != cl) {
                try {
                    Class<?> c = Class.forName(name, true, cl);
                    if (null != c) {
                        return c;
                    }
                } catch (ClassNotFoundException e) {
                    // we'll ignore this until all classloaders fail to locate the class
                }
            }
        }
        throw new ClassNotFoundException("Cannot find class: " + name);
    }

    public static ClassLoader[] getClassLoaders(ClassLoader classLoader) {
        return new ClassLoader[]{
                classLoader,
                defaultClassLoader,
                Thread.currentThread().getContextClassLoader(),
                ClassUtils.class.getClassLoader(),
                systemClassLoader};
    }

    /**
     * 获取默认类加载器
     * @return ClassLoader
     */
    public static ClassLoader getDefaultClassLoader() {
        ClassLoader cl = null;
        try {
            cl = Thread.currentThread().getContextClassLoader();
        } catch (Throwable ex) {
            LOGGER.debug("Cannot access com.hyacinth.thread context ClassLoader - falling back...");
        }
        if (cl == null) {
            cl = ClassUtils.class.getClassLoader();
            if (cl == null) {
                try {
                    cl = ClassLoader.getSystemClassLoader();
                } catch (Throwable ex) {
                    LOGGER.debug("Cannot access system ClassLoader - oh well, maybe the caller can live with null...");
                }
            }
        }
        return cl;
    }

    /**
     * 获取某个类的方法
     * @param clazz the clazz to analyze
     * @param methodName the name of the method
     * @param paramTypes the parameter types of the method
     * @return the method, or {@code null} if not found
     * @see Class#getMethod
     */
    public static Method getMethodIfAvailable(Class<?> clazz, String methodName, Class<?>... paramTypes) {
        Assert.notNull(clazz, "类不能为空");
        Assert.notNull(methodName, "方法签名不能为空");
        Method method = null;
        if (paramTypes != null) {
            try {
                method = clazz.getMethod(methodName, paramTypes);
            } catch (NoSuchMethodException ex) {
                LOGGER.error("Expected method not found", ex);
            }
        } else {
            Set<Method> candidates = new HashSet<>(1);
            Method[] methods = clazz.getMethods();
            for (Method m : methods) {
                if (methodName.equals(m.getName())) {
                    candidates.add(m);
                }
            }
            if (candidates.size() == 1) {
                method =  candidates.iterator().next();
            } else if (candidates.isEmpty()) {
                LOGGER.error("Expected method not found: " + clazz.getName() + '.' + methodName);
            } else {
                LOGGER.error("No unique method found: " + clazz.getName() + '.' + methodName);
            }
        }
        return method;
    }

    /**
     * 检查给定类在给定上下文中是否缓存安全
     * 校验类加载器是安全的
     */
    public static boolean isCacheSafe(Class<?> clazz, ClassLoader classLoader) {
        Assert.notNull(clazz, "Class must not be null");
        try {
            ClassLoader target = clazz.getClassLoader();
            // Common cases
            if (target == classLoader || target == null) {
                return true;
            }
            if (classLoader == null) {
                return false;
            }
            // Check for match in ancestors -> positive
            ClassLoader current = classLoader;
            while (current != null) {
                current = current.getParent();
                if (current == target) {
                    return true;
                }
            }
            // Check for match in children -> negative
            while (target != null) {
                target = target.getParent();
                if (target == classLoader) {
                    return false;
                }
            }
        } catch (SecurityException ex) {
            // Fall through to loadable check below
        }
        // Fallback for ClassLoaders without parent/child relationship:
        // safe if same Class can be loaded from given ClassLoader
        return (classLoader != null && isLoadable(clazz, classLoader));
    }

    private static boolean isLoadable(Class<?> clazz, ClassLoader classLoader) {
        try {
            return (clazz == classLoader.loadClass(clazz.getName()));
            // Else: different class with same name found
        } catch (ClassNotFoundException ex) {
            // No corresponding class found at all
            return false;
        }
    }

    /**
     * 是否可转让（拷贝），相同的类或子类
     *
     * @param lhsType
     * @param rhsType
     * @return
     */
    public static boolean isAssignable(Class<?> lhsType, Class<?> rhsType) {
        Assert.notNull(lhsType, "Left-hand side type must not be null");
        Assert.notNull(rhsType, "Right-hand side type must not be null");
        // lhsType对象所表示的类或接口与rhsType所表示的类或接口是否相同，
        // 或是否是其超类或超接口。如果是则返回 true；否则返回 false
        if (lhsType.isAssignableFrom(rhsType)) {
            return true;
        }
        // 判断Class是否为原始类型（boolean、char、byte、short、int、long、float、double）
        if (lhsType.isPrimitive()) {
            Class<?> resolvedPrimitive = primitiveWrapperTypeMap.get(rhsType);
            return lhsType == resolvedPrimitive;
        } else {
            Class<?> resolvedWrapper = primitiveTypeToWrapperMap.get(rhsType);
            return resolvedWrapper != null && lhsType.isAssignableFrom(resolvedWrapper);
        }
    }

    /**
     * 比较判断types1和types2两组类，如果types1中所有的类都与types2对应位置的类相同，或者是其父类或接口，则返回<code>true</code>
     *
     * @param types1 类组1
     * @param types2 类组2
     * @return 是否相同、父类或接口
     */
    public static boolean isAllAssignableFrom(Class<?>[] types1, Class<?>[] types2) {
        if (ArrayUtils.isEmpty(types1) && ArrayUtils.isEmpty(types2)) {
            return true;
        }
        if (null == types1 || null == types2) {
            // 任何一个为null不相等（之前已判断两个都为null的情况）
            return false;
        }
        if (types1.length != types2.length) {
            return false;
        }

        Class<?> type1;
        Class<?> type2;
        for (int i = 0; i < types1.length; i++) {
            type1 = types1[i];
            type2 = types2[i];
            if (!isAssignable(type1, type2)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 设置方法为可访问
     *
     * @param method 方法
     * @return 方法
     */
    public static Method setAccessible(Method method) {
        if (null != method && !method.isAccessible()) {
            method.setAccessible(true);
        }
        return method;
    }

    /**
     * 是否为静态方法
     *
     * @param method 方法
     * @return 是否为静态方法
     */
    public static boolean isStatic(Method method) {
        Assert.notNull(method, "Method to provided is null.");
        return Modifier.isStatic(method.getModifiers());
    }

    /**
     * 判断是否为Java本地接口
     *
     * @param ifc 类
     */
    public static boolean isJavaLanguageInterface(Class<?> ifc) {
        return javaLanguageInterfaces.contains(ifc);
    }

    /**
     * 获得给定类的第一个泛型参数
     *
     * @param clazz 被检查的类，必须是已经确定泛型类型的类
     * @return {@link Class}
     */
    public static Class<?> getTypeArgument(Class<?> clazz) {
        return getTypeArgument(clazz, 0);
    }

    /**
     * 获得给定类的泛型参数
     *
     * @param clazz 被检查的类，必须是已经确定泛型类型的类
     * @param index 泛型类型的索引号，既第几个泛型类型
     * @return {@link Class}
     */
    public static Class<?> getTypeArgument(Class<?> clazz, int index) {
        final Type argumentType = TypeUtil.getTypeArgument(clazz, index);
        if (argumentType instanceof Class) {
            return (Class<?>) argumentType;
        }
        return null;
    }

    /**
     * 获得对象数组的类数组
     *
     * @param objects 对象数组，如果数组中存在{@code null}元素，则此元素被认为是Object类型
     * @return 类数组
     */
    public static Class<?>[] getClasses(Object... objects) {
        Class<?>[] classes = new Class<?>[objects.length];
        Object obj;
        for (int i = 0; i < objects.length; i++) {
            obj = objects[i];
            classes[i] = (null == obj) ? Object.class : obj.getClass();
        }
        return classes;
    }


    /**
     * 是否为标准的类<br>
     * 这个类必须：
     *
     * <pre>
     * 1、非接口
     * 2、非抽象类
     * 3、非Enum枚举
     * 4、非数组
     * 5、非注解
     * 6、非原始类型（int, long等）
     * </pre>
     *
     * @param clazz 类
     * @return 是否为标准类
     */
    public static boolean isNormalClass(Class<?> clazz) {
        return null != clazz
                && !clazz.isInterface()
                && !isAbstract(clazz)
                && !clazz.isEnum()
                && !clazz.isArray()
                && !clazz.isAnnotation()
                && !clazz.isSynthetic()
                && !clazz.isPrimitive();
    }

    /**
     * 是否为抽象类
     *
     * @param clazz 类
     * @return 是否为抽象类
     */
    public static boolean isAbstract(Class<?> clazz) {
        return Modifier.isAbstract(clazz.getModifiers());
    }

    /**
     * 获取指定类型分的默认值<br>
     * 默认值规则为：
     *
     * <pre>
     * 1、如果为原始类型，返回0
     * 2、非原始类型返回{@code null}
     * </pre>
     *
     * @param clazz 类
     * @return 默认值
     * @since 3.0.8
     */
    public static Object getDefaultValue(Class<?> clazz) {
        if (clazz.isPrimitive()) {
            if (long.class == clazz) {
                return 0L;
            } else if (int.class == clazz) {
                return 0;
            } else if (short.class == clazz) {
                return (short) 0;
            } else if (char.class == clazz) {
                return (char) 0;
            } else if (byte.class == clazz) {
                return (byte) 0;
            } else if (double.class == clazz) {
                return 0D;
            } else if (float.class == clazz) {
                return 0f;
            } else if (boolean.class == clazz) {
                return false;
            }
        }
        return null;
    }

    /**
     * 获得默认值列表
     *
     * @param classes 值类型
     * @return 默认值列表
     * @since 3.0.9
     */
    public static Object[] getDefaultValues(Class<?>... classes) {
        final Object[] values = new Object[classes.length];
        for (int i = 0; i < classes.length; i++) {
            values[i] = getDefaultValue(classes[i]);
        }
        return values;
    }

    /**
     * 加载原始类型的类。包括原始类型、原始类型数组和void
     *
     * @param name 原始类型名，比如 int
     * @return 原始类型类
     */
    public static Class<?> loadPrimitiveClass(String name) {
        Class<?> result = null;
        if (StringUtils.isNotBlank(name)) {
            name = name.trim();
            if (name.length() <= 8) {
                result = primitiveTypeNameMap.get(name);
            }
        }
        return result;
    }

    /**
     * 加载类，通过传入类的字符串，返回其对应的类名，使用默认ClassLoader并初始化类（调用static模块内容和初始化static属性）<br>
     * 扩展{@link Class#forName(String, boolean, ClassLoader)}方法，支持以下几类类名的加载：
     *
     * <pre>
     * 1、原始类型，例如：int
     * 2、数组类型，例如：int[]、Long[]、String[]
     * 3、内部类，例如：java.lang.Thread.State会被转为java.lang.Thread$State加载
     * </pre>
     *
     * @param className 类名
     * @return 类名对应的类
     * @throws UtilException 包装{@link ClassNotFoundException}，没有类名对应的类时抛出此异常
     */
    public static <T> Class<T> loadClass(String className) {
        return (Class<T>) loadClass(className, true);
    }

    /**
     * 加载类，通过传入类的字符串，返回其对应的类名，使用默认ClassLoader<br>
     * 扩展{@link Class#forName(String, boolean, ClassLoader)}方法，支持以下几类类名的加载：
     *
     * <pre>
     * 1、原始类型，例如：int
     * 2、数组类型，例如：int[]、Long[]、String[]
     * 3、内部类，例如：java.lang.Thread.State会被转为java.lang.Thread$State加载
     * </pre>
     *
     * @param name 类名
     * @param isInitialized 是否初始化类（调用static模块内容和初始化static属性）
     * @return 类名对应的类
     * @throws UtilException 包装{@link ClassNotFoundException}，没有类名对应的类时抛出此异常
     */
    public static <T> Class<T> loadClass(String name, boolean isInitialized) throws UtilException {
        return (Class<T>) loadClass(name, getDefaultClassLoader(), isInitialized);
    }

    /**
     * 加载类，通过传入类的字符串，返回其对应的类名<br>
     * 此方法支持缓存，第一次被加载的类之后会读取缓存中的类<br>
     * 加载失败的原因可能是此类不存在或其关联引用类不存在<br>
     * 扩展{@link Class#forName(String, boolean, ClassLoader)}方法，支持以下几类类名的加载：
     *
     * <pre>
     * 1、原始类型，例如：int
     * 2、数组类型，例如：int[]、Long[]、String[]
     * 3、内部类，例如：java.lang.Thread.State会被转为java.lang.Thread$State加载
     * </pre>
     *
     * @param name 类名
     * @param classLoader {@link ClassLoader}，{@code null} 则使用系统默认ClassLoader
     * @param isInitialized 是否初始化类（调用static模块内容和初始化static属性）
     * @return 类名对应的类
     * @throws UtilException 包装{@link ClassNotFoundException}，没有类名对应的类时抛出此异常
     */
    public static Class<?> loadClass(String name, ClassLoader classLoader, boolean isInitialized) throws UtilException {
        Assert.notNull(name, "Name must not be null");

        // 加载原始类型和缓存中的类
        Class<?> clazz = loadPrimitiveClass(name);
        if (clazz == null) {
            clazz = classCache.get(name);
        }
        if (clazz != null) {
            return clazz;
        }

        if (name.endsWith(ARRAY_SUFFIX)) {
            // 对象数组"java.lang.String[]"风格
            final String elementClassName = name.substring(0, name.length() - ARRAY_SUFFIX.length());
            final Class<?> elementClass = loadClass(elementClassName, classLoader, isInitialized);
            clazz = Array.newInstance(elementClass, 0).getClass();
        } else if (name.startsWith(NON_PRIMITIVE_ARRAY_PREFIX) && name.endsWith(";")) {
            // "[Ljava.lang.String;" 风格
            final String elementName = name.substring(NON_PRIMITIVE_ARRAY_PREFIX.length(), name.length() - 1);
            final Class<?> elementClass = loadClass(elementName, classLoader, isInitialized);
            clazz = Array.newInstance(elementClass, 0).getClass();
        } else if (name.startsWith(INTERNAL_ARRAY_PREFIX)) {
            // "[[I" 或 "[[Ljava.lang.String;" 风格
            final String elementName = name.substring(INTERNAL_ARRAY_PREFIX.length());
            final Class<?> elementClass = loadClass(elementName, classLoader, isInitialized);
            clazz = Array.newInstance(elementClass, 0).getClass();
        } else {
            // 加载普通类
            if (null == classLoader) {
                classLoader = getDefaultClassLoader();
            }
            try {
                clazz = Class.forName(name, isInitialized, classLoader);
            } catch (ClassNotFoundException ex) {
                // 尝试获取内部类，例如java.lang.Thread.State =》java.lang.Thread$State
                clazz = tryLoadInnerClass(name, classLoader, isInitialized);
                if (null == clazz) {
                    throw new UtilException(ex);
                }
            }
        }

        // 加入缓存并返回
        return classCache.put(name, clazz);
    }

    /**
     * 尝试转换并加载内部类，例如java.lang.Thread.State =》java.lang.Thread$State
     *
     * @param name 类名
     * @param classLoader {@link ClassLoader}，{@code null} 则使用系统默认ClassLoader
     * @param isInitialized 是否初始化类（调用static模块内容和初始化static属性）
     * @return 类名对应的类
     * @since 4.1.20
     */
    private static Class<?> tryLoadInnerClass(String name, ClassLoader classLoader, boolean isInitialized) {
        // 尝试获取内部类，例如java.lang.Thread.State =》java.lang.Thread$State
        final int lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR);
        if (lastDotIndex > 0) {// 类与内部类的分隔符不能在第一位，因此>0
            final String innerClassName = name.substring(0, lastDotIndex) + INNER_CLASS_SEPARATOR + name.substring(lastDotIndex + 1);
            try {
                return Class.forName(innerClassName, isInitialized, classLoader);
            } catch (ClassNotFoundException ex2) {
                // 尝试获取内部类失败时，忽略之。
            }
        }
        return null;
    }

    /**
     * 执行方法<br>
     * 可执行Private方法，也可执行static方法<br>
     * 执行非static方法时，必须满足对象有默认构造方法<br>
     * 非单例模式，如果是非静态方法，每次创建一个新对象
     *
     * @param <T> 对象类型
     * @param classNameWithMethodName 类名和方法名表达式，类名与方法名用<code>.</code>或<code>#</code>连接 例如：com.xiaoleilu.hutool.StrUtil.isEmpty 或 com.xiaoleilu.hutool.StrUtil#isEmpty
     * @param args 参数，必须严格对应指定方法的参数类型和数量
     * @return 返回结果
     */
    public static <T> T invoke(String classNameWithMethodName, Object[] args) {
        return invoke(classNameWithMethodName, false, args);
    }

    /**
     * 执行方法<br>
     * 可执行Private方法，也可执行static方法<br>
     * 执行非static方法时，必须满足对象有默认构造方法<br>
     *
     * @param <T> 对象类型
     * @param classNameWithMethodName 类名和方法名表达式，例如：com.xiaoleilu.hutool.StrUtil#isEmpty或com.xiaoleilu.hutool.StrUtil.isEmpty
     * @param isSingleton 是否为单例对象，如果此参数为false，每次执行方法时创建一个新对象
     * @param args 参数，必须严格对应指定方法的参数类型和数量
     * @return 返回结果
     */
    public static <T> T invoke(String classNameWithMethodName, boolean isSingleton, Object... args) {
        if (StringUtils.isBlank(classNameWithMethodName)) {
            throw new UtilException("Blank classNameDotMethodName!");
        }

        int splitIndex = classNameWithMethodName.lastIndexOf('#');
        if (splitIndex <= 0) {
            splitIndex = classNameWithMethodName.lastIndexOf('.');
        }
        if (splitIndex <= 0) {
            throw new UtilException("Invalid classNameWithMethodName [{}]!", classNameWithMethodName);
        }

        final String className = classNameWithMethodName.substring(0, splitIndex);
        final String methodName = classNameWithMethodName.substring(splitIndex + 1);

        return invoke(className, methodName, isSingleton, args);
    }

    /**
     * 执行方法<br>
     * 可执行Private方法，也可执行static方法<br>
     * 执行非static方法时，必须满足对象有默认构造方法<br>
     * 非单例模式，如果是非静态方法，每次创建一个新对象
     *
     * @param <T> 对象类型
     * @param className 类名，完整类路径
     * @param methodName 方法名
     * @param args 参数，必须严格对应指定方法的参数类型和数量
     * @return 返回结果
     */
    public static <T> T invoke(String className, String methodName, Object[] args) {
        return invoke(className, methodName, false, args);
    }

    /**
     * 查找指定类中的所有方法（包括非public方法），也包括父类和Object类的方法 找不到方法会返回<code>null</code>
     *
     * @param clazz 被查找的类
     * @param methodName 方法名
     * @param parameterTypes 参数类型
     * @return 方法
     * @throws SecurityException 无访问权限抛出异常
     */
    public static Method getDeclaredMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) throws SecurityException {
        return ReflectionUtils.getMethod(clazz, methodName, parameterTypes);
    }

    /**
     * 执行方法<br>
     * 可执行Private方法，也可执行static方法<br>
     * 执行非static方法时，必须满足对象有默认构造方法<br>
     *
     * @param <T> 对象类型
     * @param className 类名，完整类路径
     * @param methodName 方法名
     * @param isSingleton 是否为单例对象，如果此参数为false，每次执行方法时创建一个新对象
     * @param args 参数，必须严格对应指定方法的参数类型和数量
     * @return 返回结果
     */
    public static <T> T invoke(String className, String methodName, boolean isSingleton, Object... args) {
        Class<Object> clazz = loadClass(className);
        try {
            final Method method = getDeclaredMethod(clazz, methodName, getClasses(args));
            if (null == method) {
                throw new NoSuchMethodException(StringUtils.format("No such method: [{}]", methodName));
            }
            if (isStatic(method)) {
                return ReflectionUtils.invoke(null, method, args);
            } else {
                return ReflectionUtils.invoke(isSingleton ? Singleton.get(clazz) : clazz.newInstance(), method, args);
            }
        } catch (Exception e) {
            throw new UtilException(e);
        }
    }

}
